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