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