]> git.vomp.tv Git - vompclient.git/blob - vmediaview.cc
Vogel Media Player 2008-11-28
[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         break;
552       case Remote::BACK:
553       {
554         setPictureMode(false);
555         rt= 2;
556       }
557       break;
558       case Remote::YELLOW:
559       {
560         setAudioMode(true);
561       }
562     }
563     return rt;
564   } 
565   else 
566   {
567     int rt=1;
568     bool updateInfo=false;
569     //------------------------- command in mode AUDIO (i.e. audio is on top) ----------------
570     switch(command)
571     {
572       case Remote::YELLOW:
573         setAudioMode(false);
574         rt=2;
575         break;
576       case Remote::DF_UP:
577       case Remote::UP:
578         play(playall,false,VMediaList::MV_PREV);
579         rt= 2;
580         break;
581       case Remote::FORWARD:
582         if (! audioError) getPlayer()->fastForward();
583         updateInfo=true;
584         rt=2;
585         break;
586       case Remote::DF_DOWN:
587       case Remote::DOWN:
588         play(playall,false,VMediaList::MV_NEXT);
589         rt= 2;
590         break;
591       case Remote::SKIPFORWARD:
592         if (! audioError) getPlayer()->skipForward(10);
593         rt=2;
594         break;
595       case Remote::SKIPBACK:
596         if (! audioError) getPlayer()->skipBackward(10);
597         rt=2;
598         break;
599       case Remote::REVERSE:
600         rt=2;
601         break;
602       case Remote::ZERO:
603         if (! audioError) getPlayer()->jumpToPercent(0);
604         rt=2;
605         break;
606       case Remote::ONE:
607         if (! audioError) getPlayer()->jumpToPercent(10);
608         rt=2;
609         break;
610       case Remote::TWO:
611         if (! audioError) getPlayer()->jumpToPercent(20);
612         rt=2;
613         break;
614       case Remote::THREE:
615         if (! audioError) getPlayer()->jumpToPercent(30);
616         rt=2;
617         break;
618       case Remote::FOUR:
619         if (! audioError) getPlayer()->jumpToPercent(40);
620         rt=2;
621         break;
622       case Remote::FIVE:
623         if (! audioError) getPlayer()->jumpToPercent(50);
624         rt=2;
625         break;
626       case Remote::SIX:
627         if (! audioError) getPlayer()->jumpToPercent(60);
628         rt=2;
629         break;
630       case Remote::SEVEN:
631         if (! audioError) getPlayer()->jumpToPercent(70);
632         rt=2;
633         break;
634       case Remote::EIGHT:
635         if (! audioError) getPlayer()->jumpToPercent(80);
636         rt=2;
637         break;
638       case Remote::NINE:
639         if (! audioError) getPlayer()->jumpToPercent(90);
640         rt=2;
641         break;
642       case Remote::OK:
643       case Remote::GREEN:
644       {
645         if (info) {
646           destroyInfo();
647           retriggerAudioInfo=false;
648           }
649         else {
650           retriggerAudioInfo=true;
651           showAudioInfo();
652         }
653         if (getPlayer()->getState() == AudioPlayer::S_ERROR) {
654           if (playall) play(playall,false,VMediaList::MV_NEXT);
655         }
656         rt= 2;
657       }
658       break;
659       case Remote::PLAY:
660       {
661         if (! audioError) getPlayer()->unpause();
662         updateInfo=true;
663         if (getPlayer()->getState() != AudioPlayer::S_ERROR) ;
664         else if (playall) play(playall,false,VMediaList::MV_NEXT);
665         rt= 2;
666       }
667       break;
668       case Remote::PAUSE:
669         if (! audioError) getPlayer()->pause();
670         updateInfo=true;
671         rt= 2;
672         break;
673       case Remote::STOP:
674         getPlayer()->stop();
675         justPlaying=false;
676         updateInfo=true;
677         rt= 2;
678         break;
679       case Remote::BACK:
680       {
681         getPlayer()->stop();
682         playall=false;
683         retriggerAudioInfo=false;
684         justPlaying=false;
685         setAudioMode(false);
686         if (! pictureShowing) setPictureMode(false); //could have been delayed
687         rt= 2;
688       }
689       break;
690     }
691     if (audioEnabled && updateInfo) updateAudioInfo();
692     return rt;
693   }
694 }
695
696 void VMediaView::processMessage(Message* m)
697 {
698   Log::getInstance()->log("VMediaView::processMessage", Log::DEBUG, "cmd=%lu,p=%lu", m->message,m->parameter);
699   if (m->message == Message::MOUSE_MOVE)
700   {
701     ;
702   }
703   else if (m->message == Message::MOUSE_LBDOWN)
704   {
705     
706     //check if press is outside this view! then simulate cancel
707     int x=(m->parameter>>16)-getScreenX();
708     int y=(m->parameter&0xFFFF)-getScreenY();
709     if (x<0 || y <0 || x>(int)getWidth() || y>(int)getHeight())
710     {
711       BoxStack::getInstance()->handleCommand(Remote::BACK); //simulate cancel press
712     }
713   }
714   else if (m->message = Message::PLAYER_EVENT) {
715     switch (m->parameter) {
716       case EVENT_SLIDESHOW:
717         if (! pictureEnabled) break; //old timer msg...
718         //if (! audioEnabled) {
719         if (true) {
720           if (slideshow) {
721             rotate=WJpeg::ROT_0;
722             showPicture(VMediaList::MV_NEXT,true,false);
723             startSlideshow();
724           }
725         }
726         break;
727       case EVENT_DRAWINGERROR:
728         drawingDone(true);
729         break;
730       case EVENT_DRAWINGDONE:
731         drawingDone(false);
732         break;
733       case EVENT_DIRECTORYDONE:
734         //just disable audio without (poetntially) hiding us
735         //this gives the list a chance to decide whether audio
736         //should be on top afterwards without showing the list
737         //immediately
738         setAudioMode(false,false);
739         parent->directoryDone();
740         if (! pictureShowing) setPictureMode(false);
741         if (! justPlaying) setAudioMode(false);
742         break;
743       case AudioPlayer::STREAM_ERR:
744       case AudioPlayer::STREAM_END:
745         if (playall) play(playall,false,VMediaList::MV_NEXT);
746         else {
747           setAudioMode(false);
748           justPlaying=false;
749         }
750         break;
751       case AudioPlayer::SHORT_UPDATE:
752                                 if (info && audioEnabled ) {
753                                         drawAudioClocks();
754                                         BoxStack::getInstance()->update(info,&clocksRegion);
755                                   BoxStack::getInstance()->update(info,&barRegion);
756                                         Timers::getInstance()->setTimerD(this, 4, 1);
757                                 }
758         break;
759       case AudioPlayer::NEW_SONG:
760         if (audioEnabled) updateAudioInfo();
761         break;
762       case AudioPlayer::CONNECTION_LOST:
763         if (audioEnabled) destroyInfo();
764         if (AudioPlayer *player=getPlayer(false)) {
765           player->shutdown();
766           player=NULL;
767         }
768         Command::getInstance()->connectionLost();
769         break;
770     }
771   }
772 }
773
774
775 VMediaView * VMediaView::createViewer(VMediaList * mparent) {
776    Log::getInstance()->log("VMediaView::createViewer", Log::DEBUG, "p=%p",
777         mparent);
778    VMediaView *vmn=new VMediaView(mparent);
779    BoxStack::getInstance()->add(vmn);
780    vmn->draw();
781    BoxStack::getInstance()->update(vmn);
782    return vmn;
783 }
784
785 void VMediaView::startSlideshow() {
786    slideshow=true;
787    if (! pictureLoading) Timers::getInstance()->setTimerD(this,1,showtime);
788 }
789
790 void VMediaView::stopSlideshow(bool hard) {
791    if (hard) slideshow=false;
792    Timers::getInstance()->cancelTimer(this,1);
793 }
794
795
796 void VMediaView::showPicture(ULONG move,bool bslideshow,bool activateBanner) {
797   pictureShowing=true;
798   setPictureMode(true);
799   stopSlideshow(true);
800 #ifdef DRAWING_THREAD
801   drawingThread->stop();
802 #endif
803   slideshow=bslideshow;
804   Media *newPicture=parent->getMedia(MEDIA_TYPE_PICTURE,move);
805   if ( ! newPicture) {
806     pictureShowing=false;
807     if (!audioEnabled) {
808       //within the event handler first directoryDone is called
809       //and afterwards everything is stopped if nothing new
810       sendCommandMsg(EVENT_DIRECTORYDONE);
811     }
812     slideshow=false;
813   }
814   else 
815   {
816     pictureShowing=true;
817     if (currentPicture) {
818       delete currentPicture;
819       currentPicture=NULL;
820     }
821     currentPicture=newPicture;
822     loadPicture(currentPicture,activateBanner);
823   }
824 }
825
826 //the real picture drawing method
827 //will start drawing on a new surface and will switch it wehn done
828
829 int VMediaView::loadPicture(Media *md,bool activateBanner) {
830   pictureError=NULL;
831   if (! md) return 1;
832   if (! md->getURI()) {
833     pictureError=tr("No media found");
834     Log::getInstance()->log("VMediaView::load",Log::ERR,"no URI in media");
835     return 1;
836   }
837   Log::getInstance()->log("VMediaView::load", Log::DEBUG, "filename=%s,p=%p",
838         md->getURI()->getName(),this);
839   //do we have a pictureBanner?
840   havePictureBanner=pictureBanner!=NULL || activateBanner;
841   pictureLoading=true;
842 #ifdef DRAWING_THREAD
843   if (!audioEnabled && havePictureBanner ) showPictureBanner(true);
844   drawingThread->stop();
845 #else
846   showPictureBanner(true);
847 #endif
848   ireader->stop();
849   ULLONG size=0;
850   int rtok=reader->initRead(md->getURI(),&size,ctl.scaleAmount); //scaleAmount is the same for both...
851   if (rtok == 0) {
852      //now we can really draw
853      //get the surface for drawing
854      Surface * drawSurface=NULL;
855      WJpeg::JpegControl *drawCtl=NULL;
856      getDrawingParam(drawSurface,drawCtl);
857      drawCtl->error[0]=0;
858      drawCtl->rotation=rotate;
859      drawCtl->mode=cropmode;
860      drawCtl->compressedSize=size;
861 #ifdef DRAWING_THREAD
862      bool ok=drawingThread->start(drawCtl,drawSurface,reader,pictureBack);
863      if (! ok) {
864        Log::getInstance()->log("VMediaView::load", Log::ERR, "unable to start drawing thread");
865        pictureError=tr("JpegError");
866        pictureLoading=false;
867        destroyPictureBanner();
868        return 1;
869      }
870      return 0;
871 #else
872      //here we could hand this over to the drawing thread
873      bool ok=WJpeg::drawJpeg(drawCtl,drawSurface,reader,pictureBack);
874      drawingDone(!ok);
875      return ok?0:1;
876 #endif
877   }
878   pictureLoading=false;
879   return 1;
880 }
881
882 void VMediaView::drawingDone(bool hasError) {
883   pictureLoading=false;
884   destroyPictureBanner(); //disable loading indication (or real banner)
885   if (! hasError) {
886     switchSurface();
887     Log::getInstance()->log("VMediaView::drawingDone", Log::DEBUG, "success: sfc now=%p",surface);
888     pictureError=NULL;
889     //only show the pictureBanner if it was there before
890     if (havePictureBanner && ! audioEnabled) showPictureBanner();
891     Log::getInstance()->log("VMediaView::load", Log::DEBUG, "success" );
892     updatePictureInfo(); //will only do somethng if pictureEnabled
893   }
894   else 
895   {
896     pictureError=tr("JpegError");
897     if (pictureEnabled) {
898       draw();
899       destroyInfo();
900     }
901   }
902   MediaPlayer::getInstance()->closeMediaChannel(1);
903 #ifndef DRAWING_THREAD
904   if (audioEnabled) showAudioBanner();
905 #endif
906   if (slideshow) startSlideshow();
907   BoxStack::getInstance()->update(this);
908 }
909
910 void VMediaView::showPictureBanner(bool loading) {
911   //we are in the main thread - so we can (and must) safely hard destroy/create the banner
912   Timers::getInstance()->cancelTimer(this,2);
913   if (! currentPicture) {
914     //hmm...
915     destroyPictureBanner(false);
916     return;
917     }
918   if (pictureBanner) destroyPictureBanner(false);
919   if (! pictureEnabled || ! bannerEnabled) return;
920   pictureBanner= new VPictureBanner(loading, slideshow);
921   pictureBanner->fillColour(infoBack);
922   if (! loading) {
923     int len=strlen(currentPicture->getFileName())+Media::TIMEBUFLEN+20;
924     char *buf=new char[len];
925     char tbuf[Media::TIMEBUFLEN];
926     SNPRINTF(buf,len,"%c%02ds%c %s %s " ,
927       slideshow?' ':'[',
928       showtime,
929       slideshow?' ':']',
930       currentPicture->getTimeString(tbuf),
931       currentPicture->getFileName()
932       );
933     pictureBanner->setText(buf);
934     delete [] buf;
935   }
936   else {
937     char *buf=new char[strlen(currentPicture->getDisplayName())+50];
938     SNPRINTF(buf,50,"%s %s",tr("Loading"), currentPicture->getDisplayName());
939     pictureBanner->setText(buf);
940     delete buf;
941   }
942   pictureBanner->draw();
943   if (! loading )   Timers::getInstance()->setTimerD(this,2,8);
944   BoxStack::getInstance()->add(pictureBanner);
945   BoxStack::getInstance()->update(pictureBanner);
946   }
947
948 void VMediaView::destroyPictureBanner(bool fromTimer) {
949   if (pictureBanner) {
950     if (fromTimer) sendViewMsg(pictureBanner); 
951     else BoxStack::getInstance()->remove(pictureBanner);
952     pictureBanner=NULL;
953     if (! fromTimer) Timers::getInstance()->cancelTimer(this,2);
954     }
955 }
956 void VMediaView::updatePictureBanner(bool loading) {
957   if (pictureBanner ) {
958     showPictureBanner(loading);
959     }
960 }
961 void VMediaView::timercall(int clientref) {
962    Log::getInstance()->log("VMediaView::timercall", Log::DEBUG, "id=%d",clientref);
963    switch(clientref)
964    {
965       case 4:
966         {
967           sendCommandMsg(AudioPlayer::SHORT_UPDATE);
968           break;
969         }
970       case 3:
971         {
972           Log::getInstance()->log("VMediaView::timercall", Log::DEBUG, "infoEnd");
973           destroyInfo(true);
974           if (audioEnabled) {
975             //we only did show the audio error info if audio is enabled
976             bool stillError=false;
977             if (AudioPlayer * player=getPlayer(false)) {
978               stillError=player->getState()==AudioPlayer::S_ERROR;
979             }
980             if (stillError) {
981               sendCommandMsg(AudioPlayer::STREAM_END);
982             }
983           }
984           break;
985         }
986       case 1:
987         if (! slideshow) return;
988         Log::getInstance()->log("VMediaView::timercall", Log::DEBUG, "slideshow");
989         sendCommandMsg(EVENT_SLIDESHOW);
990         break;
991       case 2:
992         Log::getInstance()->log("VMediaView::timercall", Log::DEBUG, "pictureBannerEnd");
993         destroyPictureBanner(true);
994         break;
995     }
996    
997   }
998
999 #define INFOBUF 2000
1000 void VMediaView::showPictureInfo(){
1001   if (! pictureEnabled || audioEnabled) return;
1002   if (info) destroyInfo();
1003   if (! currentPicture) return;
1004
1005   info=new VInfo();
1006   info->setTitleText(currentPicture->getFileName());
1007   info->setDropThrough();
1008   info->setSize(500, 300);
1009   info->createBuffer();
1010   info->setBorderOn(1);
1011   info->setTitleBarOn(1);
1012
1013   if (Video::getInstance()->getFormat() == Video::PAL)
1014         info->setPosition(100, 180);
1015   else
1016         info->setPosition(100, 150);
1017   char buf[INFOBUF];
1018   char tbuf[Media::TIMEBUFLEN];
1019   //modes should come from mediaoptions...
1020   const char *mode=NULL;
1021   switch (currentControl->mode) {
1022     case WJpeg::CROPPERCENT:
1023       mode="clipfactor";
1024       break;
1025     case WJpeg::LETTER:
1026       mode="letter";
1027       break;
1028     default:
1029       mode="clip";
1030       break;
1031   }
1032   const char *dirname=parent->getDirname(MEDIA_TYPE_PICTURE);
1033   int ldir=0;
1034   const char *prfx="";
1035   if (dirname) ldir=strlen(dirname);
1036   if (ldir > 35){
1037     dirname=dirname+ldir-35;
1038     prfx="...";
1039   }
1040   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",
1041      tr("Directory"), prfx,dirname,
1042      tr("Format(px)"),currentControl->picw,currentControl->pich,
1043      tr("Filesize"),currentControl->compressedSize/1000,
1044      tr("Time"),currentPicture->getTimeString(tbuf),
1045      tr("Rotation"),90*currentControl->finalRotation,
1046      tr("Scale"),currentControl->scale,
1047      tr("Picture Mode"),mode );
1048   info->setMainText(buf);
1049   info->draw();
1050   BoxStack::getInstance()->add(info);
1051   BoxStack::getInstance()->update(info);
1052   Timers::getInstance()->setTimerD(this,3,8);
1053 }
1054 void VMediaView::updatePictureInfo(){
1055   if (info) {
1056     showPictureInfo();
1057     }
1058 }
1059 void VMediaView::destroyInfo(bool fromTimer){
1060   if (info) {
1061     if (! fromTimer) {
1062       Log::getInstance()->log("VMediaView",Log::DEBUG,"remove info %p",info);
1063       BoxStack::getInstance()->remove(info);
1064     }
1065     else {
1066       Log::getInstance()->log("VMediaView",Log::DEBUG,"trigger remove info %p",info);
1067       sendViewMsg(info);
1068     }
1069     info=NULL;
1070     }
1071   if (! fromTimer) Timers::getInstance()->cancelTimer(this,3);
1072   if (! fromTimer) Timers::getInstance()->cancelTimer(this,4);
1073 }
1074
1075 void VMediaView::sendViewMsg(Boxx *v) {
1076   Message* m = new Message(); 
1077   m->message = Message::CLOSE_ME;
1078   m->to = BoxStack::getInstance();
1079   m->from = v;
1080   m->parameter=(ULONG)v;
1081   Command::getInstance()->postMessageFromOuterSpace(m);
1082 }
1083 void VMediaView::sendCommandMsg(int command) {
1084   Message* m = new Message(); 
1085   //we misuse PLAYER_EVENT here
1086   m->message = Message::PLAYER_EVENT;
1087   m->to = this;
1088   m->from = this;
1089   m->parameter= command;
1090   Command::getInstance()->postMessageFromOuterSpace(m);
1091 }
1092
1093 void VMediaView::enableBanner(bool enable) {
1094   bannerEnabled=false;
1095   updatePictureBanner();
1096 }
1097
1098 void VMediaView::getDrawingParam(Surface *&sfc,WJpeg::JpegControl *&c){
1099   if (secondSurface()) {
1100     //we currently display on sfc2
1101     sfc=sfc1;
1102     c=&ctl;
1103   }
1104   else {
1105     sfc=sfc2;
1106     c=&ctl2;
1107   }
1108 }
1109 void VMediaView::switchSurface(){
1110   if (secondSurface()) {
1111     //now we switch to sfc1
1112     surface=sfc1;
1113     currentControl=&ctl;
1114   }
1115   else {
1116     surface=sfc2;
1117     currentControl=&ctl2;
1118   }
1119 }
1120
1121 AudioPlayer * VMediaView::getPlayer(bool createIfNeeded)
1122 {
1123   AudioPlayer* rt=AudioPlayer::getInstance(this,false);
1124   if (! createIfNeeded && rt == NULL) return NULL;
1125   if (rt == NULL) {
1126     rt=AudioPlayer::getInstance(this);
1127     rt->run();
1128   }
1129   return rt;
1130 }
1131
1132 bool VMediaView::isAudioPlaying() {
1133   Log::getInstance()->log("VMediaView::isPlaying", Log::DEBUG, "rt=%s", justPlaying?"true":"false");
1134   return justPlaying;
1135 }
1136
1137
1138
1139
1140
1141
1142 int VMediaView::play(bool all,bool activate,ULONG move,bool showInfo) {
1143   int rt=0;
1144   if (getPlayer(false)) getPlayer(false)->stop();
1145   justPlaying=false;
1146   if (currentAudio) delete currentAudio;
1147   currentAudio=NULL;
1148   playall=all;
1149   currentAudio=parent->getMedia(MEDIA_TYPE_AUDIO,move);
1150   audioError=NULL;
1151   if ( ! currentAudio || ! currentAudio->getURI()) {
1152     Log::getInstance()->log("VMediaView::load", Log::ERR, "no URI in media");
1153     audioError=tr("no audio file");
1154     if (audioEnabled) sendCommandMsg(EVENT_DIRECTORYDONE);
1155     rt= -1;
1156   }
1157   else {
1158     Log::getInstance()->log("VMediaView::load", Log::DEBUG, "filename=%s,p=%p",
1159       currentAudio->getURI()->getName(),this);
1160     int wseq=getPlayer()->play(currentAudio->getURI());
1161     if (getPlayer()->waitForSequence(5,wseq)<0) {
1162        audioError=tr("unable to open audio file");
1163        rt= -1;
1164     }
1165     else {
1166       justPlaying=true;
1167       rt=0;
1168     }
1169     Log::getInstance()->log("VMediaView", Log::DEBUG, "player started for %s",currentAudio->getURI()->getName());
1170   }
1171   if (activate && ! audioEnabled){
1172     if (showInfo) retriggerAudioInfo=true;
1173     setAudioMode(true);
1174   }
1175   else {
1176     //avoid duplicate creation of banner and info
1177     showAudioBanner();
1178     showAudioInfo();
1179   }
1180   if (activate && (! currentPicture || ! pictureShowing)) draw();
1181   BoxStack::getInstance()->update(this);
1182   return rt;
1183 }
1184
1185 void VMediaView::showAudioInfo() {
1186   if (! audioEnabled) return;
1187   Timers::getInstance()->cancelTimer(this,4);
1188   Timers::getInstance()->cancelTimer(this,3);
1189   if (info) destroyInfo();
1190   if (! retriggerAudioInfo) return;
1191   drawAudioInfo();
1192   bool playerError=getPlayer()->getState()==AudioPlayer::S_ERROR || audioError;
1193   if (! playerError) Timers::getInstance()->setTimerD(this,3,AUDIOBANNER_TIME);
1194   else Timers::getInstance()->setTimerD(this,3,AUDIOERROR_TIME);
1195         if (! playerError) Timers::getInstance()->setTimerD(this,4, 1);
1196   BoxStack::getInstance()->update(info);
1197   }
1198
1199 void VMediaView::updateAudioInfo() {
1200   if (info) {
1201     showAudioInfo();
1202     }
1203 }
1204
1205 void VMediaView::drawAudioInfo(){
1206   Log::getInstance()->log("VMediaView",Log::DEBUG, "draw banner for %p",info);
1207   const char *title=NULL;
1208   char *playerTitle=NULL;
1209   bool playerError=false;
1210   int numlines=0;
1211   int len=0;
1212   int num=0;
1213   const char *pl=tr("Playlist");
1214   const char *first=NULL;
1215   char *playerInfo=NULL;
1216   if (audioError) {
1217     if (getPlayer()->getState() == AudioPlayer::S_PLAY) audioError=NULL;
1218   }
1219   if (! currentAudio && ! audioError) audioError=tr("no audio file");
1220   if (audioError ) {
1221     title=tr("MediaError");
1222   }
1223   else {
1224     playerTitle=getPlayer()->getTitle();
1225     if (playerTitle) title=playerTitle;
1226     else title=currentAudio->getDisplayName();
1227     num=parent->getNumEntries(MEDIA_TYPE_AUDIO,currentAudio->index);
1228     playerError=getPlayer()->getState() == AudioPlayer::S_ERROR;
1229     //1more line for long dirs
1230     numlines=playall?5:4;
1231   }
1232   if (playerError) {
1233     numlines=3;
1234     first=tr("Unable to play audio file");
1235     len=strlen(first)+3;
1236   }
1237   else if (audioError) {
1238     numlines=3;
1239     first=audioError;
1240     len=strlen(first)+3;
1241   }
1242   else {
1243     playerInfo=getPlayer()->getID3Info();drawText(tr("Loading"),5,3,Colour::LIGHTTEXT);
1244     len=strlen(currentAudio->getDisplayName())+strlen(pl)+30+strlen(parent->getDirname(MEDIA_TYPE_AUDIO))+Media::TIMEBUFLEN+110;
1245     if (playerInfo) {
1246       for (UINT i=0;i<strlen(playerInfo);i++) 
1247         if (playerInfo[i] == '\n') numlines++;
1248       len+=strlen(playerInfo);
1249       first=playerInfo;
1250     }
1251     else {
1252       first="";
1253     }
1254   }
1255   destroyInfo();
1256   info=new VInfo();
1257   UINT height=numlines*30+60;
1258   UINT vheight=Video::getInstance()->getScreenHeight();
1259   UINT vwidth=Video::getInstance()->getScreenWidth();
1260   if (height > vheight-2*AUDIOBANNER_BOTTOM_MARGIN)
1261     height=vheight-2*AUDIOBANNER_BOTTOM_MARGIN;
1262   info->setSize(vwidth -2*AUDIOBANNER_X_MARGIN, height);
1263   info->createBuffer();
1264   if (Video::getInstance()->getFormat() == Video::PAL)
1265   {
1266     info->setPosition(AUDIOBANNER_X_MARGIN, vheight-height-AUDIOBANNER_BOTTOM_MARGIN);
1267   }
1268   else
1269   {
1270     info->setPosition(AUDIOBANNER_X_MARGIN, vheight-height-AUDIOBANNER_BOTTOM_MARGIN);
1271   }
1272
1273   info->setTitleBarOn(0);
1274   info->setDropThrough();
1275   //from vvideorec 
1276         //set the regions for the closcks and bars on banner
1277   barRegion.x = info->getWidth()-AUDIOBARLEN-20;
1278   barRegion.y = info->getHeight() - 30;   // FIXME, need to be - 1? and below?
1279   barRegion.w = info->getWidth()-AUDIOBARLEN+10;
1280   barRegion.h = 30;
1281
1282   clocksRegion.x = 130;
1283   clocksRegion.y = barRegion.y + 3;
1284   clocksRegion.w = 190;
1285   clocksRegion.h = surface->getFontHeight();
1286   Log::getInstance()->log("VMediaView",Log::DEBUG,"created AudioInfo %p",info);
1287   BoxStack::getInstance()->add(info);
1288   char *buf=new char [len];
1289   if (playerError || audioError) {
1290     SNPRINTF(buf,len,"%s",first);
1291   }
1292   else {
1293     char tbuf[Media::TIMEBUFLEN];
1294     if (playall) {
1295     SNPRINTF(buf,len,"%s\n"
1296         "%s:%s\n"
1297         "%s: %d/%d\n"
1298         "%s:%s\n"
1299         "%s:%s\n",
1300         first,
1301         tr("FileName"),currentAudio->getDisplayName(),
1302         pl,num,parent->getNumEntries(MEDIA_TYPE_AUDIO),
1303         tr("Directory"),parent->getDirname(MEDIA_TYPE_AUDIO),
1304         tr("Time"),currentAudio->getTimeString(tbuf));
1305     }
1306     else {
1307     SNPRINTF(buf,len,"%s\n"
1308         "%s:%s\n"
1309         "%s:%s\n"
1310         "%s:%s\n",
1311         first,
1312         tr("FileName"),currentAudio->getDisplayName(),
1313         tr("Directory"),parent->getDirname(MEDIA_TYPE_AUDIO),
1314         tr("Time"),currentAudio->getTimeString(tbuf));
1315     }
1316   }
1317   Log::getInstance()->log("VMediaView",Log::DEBUG,"info: (%d)%s",strlen(buf),buf);
1318   //now the real drawing functions
1319   info->draw();
1320   //title
1321   info->rectangle(0, 0, info->getWidth(), 30, Colour::TITLEBARBACKGROUND);
1322   info->drawText(title, 5, 5, Colour::LIGHTTEXT);
1323   info->drawPara(buf,5,32,Colour::LIGHTTEXT);
1324   delete [] buf;
1325   if (! audioError) {
1326     WSymbol w;
1327     info->TEMPADD(&w);
1328     int x=10;
1329     int ybottom=info->getHeight();
1330     info->rectangle(0, ybottom - barRegion.h, info->getWidth(), barRegion.h, Colour::TITLEBARBACKGROUND);
1331     bool drawSymbol=true;
1332     switch(getPlayer()->getState()) {
1333       case AudioPlayer::S_PAUSE:
1334         w.nextSymbol = WSymbol::PAUSE;
1335         break;
1336       case AudioPlayer::S_PLAY:
1337         w.nextSymbol = WSymbol::PLAY;
1338         break;
1339       case AudioPlayer::S_DONE:
1340         if (playall) 
1341           w.nextSymbol = WSymbol::PLAY;
1342         else
1343           drawSymbol=false;
1344         break;
1345       case AudioPlayer::S_BACK:
1346         w.nextSymbol = WSymbol::FBWD ;
1347         break;
1348       case AudioPlayer::S_FF:
1349         w.nextSymbol = WSymbol::FFWD ;
1350         break;
1351       default:
1352         drawSymbol=false;
1353         break;
1354     }
1355     if (drawSymbol) {
1356       w.setPosition(x, ybottom-24);
1357       w.draw();
1358     }
1359     else {
1360       //stop symbol
1361       info->rectangle(x, ybottom - 23, 18, 16, Colour::LIGHTTEXT);
1362     }
1363     x+=30;
1364     drawAudioClocks();
1365   }
1366   if (playerInfo) delete playerInfo;
1367   if (playerTitle) delete playerTitle;
1368 }
1369
1370 void VMediaView::drawAudioClocks() {
1371         if (! info || ! audioEnabled) return;
1372         Log::getInstance()->log("VMediaView::drawAudioClocks", Log::DEBUG, "");
1373   //draw clocks and bar
1374   info->rectangle(clocksRegion, Colour::TITLEBARBACKGROUND);
1375
1376   time_t currentSec = (time_t)(getPlayer()->getCurrentTimes());
1377   time_t lengthSec=(time_t)(getPlayer()->getSonglen());
1378         struct tm cpos;
1379         struct tm slen;
1380 /*      gmtime_r(&currentSec,&cpos);
1381         gmtime_r(&lengthSec,&slen);*/
1382     cpos.tm_hour=currentSec/3600;
1383     cpos.tm_min=(currentSec-cpos.tm_hour*3600)/60;
1384     cpos.tm_sec=(currentSec-cpos.tm_hour*3600-cpos.tm_min*60);
1385     slen.tm_hour=lengthSec/3600;;
1386     slen.tm_min=(lengthSec-slen.tm_hour*3600)/60;
1387     slen.tm_sec=(lengthSec-slen.tm_hour*3600-slen.tm_min*60);
1388
1389   char buffer[100];
1390   if (currentSec >= lengthSec)
1391   {
1392     SNPRINTF(buffer,99, "-:--:-- / -:--:--  %03dk",getPlayer()->getCurrentBitrate()/1000);
1393   }
1394   else
1395   {
1396     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,
1397                                 getPlayer()->getCurrentBitrate()/1000);
1398                 //Log::getInstance()->log("VMediaView", Log::DEBUG, buffer);
1399   }
1400
1401   info->drawText(buffer, clocksRegion.x, clocksRegion.y, Colour::LIGHTTEXT);
1402   
1403         // Draw progress bar
1404   int progBarXbase = 0;
1405         int barlen=250;
1406
1407   info->rectangle(barRegion.x + progBarXbase, barRegion.y + 3, barlen+10, 24, Colour::LIGHTTEXT);
1408   info->rectangle(barRegion.x + progBarXbase + 2, barRegion.y + 5, barlen+6, 20, barBlue);
1409
1410   if (currentSec > lengthSec) currentSec=lengthSec;
1411   if (lengthSec == 0) return;
1412
1413   // Draw yellow portion
1414   int progressWidth = (barlen+2) * currentSec / lengthSec;
1415   info->rectangle(barRegion.x + progBarXbase + 4, barRegion.y + 7, progressWidth, 16, Colour::SELECTHIGHLIGHT);
1416
1417 }
1418
1419 void VMediaView::showAudioBanner() {
1420   destroyAudioBanner();
1421   if (! audioEnabled) return;
1422   audioBanner=new VInfo();
1423   Log::getInstance()->log("VMediaView",Log::DEBUG,"creating AudioBanner %p", audioBanner);
1424   Video *v=Video::getInstance();
1425   audioBanner->setSize(v->getScreenWidth()-100, 36);
1426   audioBanner->createBuffer();
1427   audioBanner->setPosition(50, v->getScreenHeight()-50);
1428   audioBanner->fillColour(audioBannerBack);
1429   audioBanner->setTitleBarOn(0);
1430   audioBanner->setDropThrough();
1431   if ( ! currentAudio || ! currentAudio->getDisplayName() || audioError) {
1432     audioBanner->drawText(tr("AudioPlayer - not playing"),5,3,Colour::LIGHTTEXT);
1433   }
1434   else {
1435     char * buf=new char[strlen(currentAudio->getDisplayName())+50];
1436     SNPRINTF(buf,50,"%s %s",tr("AudioPlayer"),currentAudio->getDisplayName());
1437     audioBanner->drawText(buf,5,3,Colour::LIGHTTEXT);
1438     delete buf;
1439   }
1440   BoxStack::getInstance()->add(audioBanner);
1441   BoxStack::getInstance()->update(audioBanner);
1442 }
1443
1444 void VMediaView::destroyAudioBanner() {
1445   if (audioBanner) {
1446     Log::getInstance()->log("VMediaView",Log::DEBUG,"deleting AudioBanner %p",audioBanner);
1447     BoxStack::getInstance()->remove(audioBanner);
1448     audioBanner=NULL;
1449   }
1450 }