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