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