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